
import 'dart:async';

import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio/dio.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
import 'package:flutter/foundation.dart';
import 'package:home/generated/json/base/json_convert_content.dart';
import 'package:home/page/router.dart';
import 'package:home/platform/web_html_placeholder.dart' if(dart.library.html) 'dart:html' as document;
import 'package:home/utils/loger.dart';
import 'package:path_provider/path_provider.dart';

import 'base_response_entity.dart';

class NetWork{
  static NetWork? _net;
  static const String _hostName = "router.my-nas.icu";
  static const String _baseUrl = "http://router.my-nas.icu:19000";
  static NetWork getInstance(){
    _net ??= NetWork();
    return _net??NetWork();
  }

  ///网络请求框架
  final Dio _dio = Dio();
  ///cookies 管理
  PersistCookieJar? _persistCookieJar;
  NetWork(){
    print("初始化网络库");
    _dio.options
      ..baseUrl = _baseUrl
      ..connectTimeout = 3000
      ..receiveTimeout = 6000;
    _dio.interceptors
      .add(LogInterceptor());
    // initCookiesStore();
  }

  Future<BaseResponse<T>> post<T>(
      String path, {
        data,
        Map<String, dynamic>? queryParameters,
        Options? options,
        CancelToken? cancelToken,
        ProgressCallback? onSendProgress,
        ProgressCallback? onReceiveProgress,
      }) async {
    return _dio.post(path,
                data: data,
                queryParameters: queryParameters,
                options: options,
                cancelToken: cancelToken,
                onSendProgress: onSendProgress,
                onReceiveProgress: onReceiveProgress
            ).then<BaseResponse<T>>((value){
              return createResponseData<T>(value);
            });

  }

  Future<BaseResponse<T>> get<T>(String path,{
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onReceiveProgress,
  }) async{
    return _dio.get(path,
       queryParameters: queryParameters,
       options: options,
       cancelToken: cancelToken,
       onReceiveProgress: onReceiveProgress
     ).then<BaseResponse<T>>((value){
       return createResponseData(value);
     });
  }

  BaseResponse<T> createResponseData<T>(Response response){
    BaseResponse<T> baseResponse = BaseResponse.baseResponseEntityFromJson(response.data);
    var tmpData = response.data["data"];
    if(null != tmpData) {
      baseResponse.data = JsonConvert.fromJsonAsT<T>(tmpData);
    }
    return baseResponse;
  }

  initCookiesStore() async {
    if(null == _persistCookieJar) {
      var cookiesPath = await getApplicationSupportDirectory();
      print("存储路径：${cookiesPath.path}");
      _persistCookieJar = PersistCookieJar(
          storage: FileStorage("${cookiesPath.path}/flutter/cookies1"));
      _dio.interceptors
          .add(CookieManager(_persistCookieJar!));
    }
  }

  ///是否含有登录之后的cookies
  Future<bool> hasLoginCookies() async {
    String? read;
    if(kIsWeb == true){
      read = await Future.value(document.document.cookie);
    }else{
      ///初始化cookies
      await initCookiesStore();
      await _persistCookieJar?.storage.init(true,false);
      read = await _persistCookieJar?.storage.read(_hostName);
    }
    logger.info("cookies: ${read}");
    if(read != null) {
      bool hasCookies = read.contains("user_cookies");
      if(hasCookies) return true;
    }
    await Future.delayed(Duration(milliseconds: 2000));
    return false;
  }
}

typedef EnqueueCallback = FutureOr Function(bool);

class Lock {
  Future? _lock;

  late Completer _completer;

  bool get locked => _lock != null;

  void lock() {
    if (!locked) {
      _completer = Completer();
      _lock = _completer.future;
    }
  }

  void unlock(bool islogin) {
    if (locked) {
      _completer.complete(islogin);
      _lock = null;
    }
  }

  void clear([String msg = 'cancelled']) {
    if (locked) {
      _completer.completeError(msg);
      _lock = null;
    }
  }

  /// If the interceptor is locked, the incoming request/response task
  /// will enter a queue.
  ///
  /// [callback] the function  will return a `Future`
  /// @nodoc
  Future? enqueue(EnqueueCallback callback) {
    if (locked) {
      // we use a future as a queue
      return _lock!.then((d) => callback(d));
    }
    return null;
  }
}

class LogInterceptor extends Interceptor{

  var _lock = Lock();
  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    super.onRequest(options, handler);
  }

  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) async {
    if(response.data["code"] == 304){
      logger.warning("登陆超时 重新登陆");
      var dio = NetWork.getInstance()._dio;
      if(!_lock.locked) {
        _lock.lock();
        StationRouter.navigatorKey.currentState?.pushNamed(StationRouter.login,arguments: {"channel","login_timeout"}).then((value){
          logger.warning("登陆${(value==true?"成功":"失败")}");
          if(value == true){
            _lock.unlock(true);
          }else{
            _lock.unlock(false);
          }
        });
      }
      logger.warning("登陆超时 await 所有请求");
      await _lock.enqueue((d) async{
          if(d == true){
            logger.warning("登陆${(d==true?"成功开始重新请求":"失败取消所有请求")}");
            var options = response.requestOptions;
            Response newResponse = await dio.request(options.path,
              queryParameters: options.queryParameters,
              options: checkOptions(options.method,null),
              onReceiveProgress: options.onReceiveProgress,
              onSendProgress: options.onSendProgress
            );
            logger.warning("重新请求结果${newResponse}");
            handler.next(newResponse);
          }else{
            handler.next(response);
          }
      });
    }else{
      super.onResponse(response, handler);
    }
  }

  static Options checkOptions(method, options) {
    options ??= Options();
    options.method = method;
    return options;
  }
}